<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>线程池 | JavaPool</title>
    <meta name="generator" content="VuePress 1.9.2">
    <link rel="icon" href="/img/favicon.ico">
    <meta name="description" content="java pool icu">
    <meta name="keywords" content="vuepress,theme,blog,vdoing">
    <meta name="theme-color" content="#a1cd00">
    
    <link rel="preload" href="/assets/css/0.styles.6964efbe.css" as="style"><link rel="preload" href="/assets/js/app.c5f14b06.js" as="script"><link rel="preload" href="/assets/js/2.0bb8723e.js" as="script"><link rel="preload" href="/assets/js/6.634b1bae.js" as="script"><link rel="prefetch" href="/assets/js/10.56cf0803.js"><link rel="prefetch" href="/assets/js/11.3f64ae04.js"><link rel="prefetch" href="/assets/js/12.02afd2cb.js"><link rel="prefetch" href="/assets/js/13.635b7092.js"><link rel="prefetch" href="/assets/js/14.f10556e8.js"><link rel="prefetch" href="/assets/js/15.27d8470a.js"><link rel="prefetch" href="/assets/js/16.70efe620.js"><link rel="prefetch" href="/assets/js/17.a79eaec6.js"><link rel="prefetch" href="/assets/js/18.aa4c8485.js"><link rel="prefetch" href="/assets/js/19.d98d039e.js"><link rel="prefetch" href="/assets/js/20.31b4dba4.js"><link rel="prefetch" href="/assets/js/21.c5f5372e.js"><link rel="prefetch" href="/assets/js/3.36e473cd.js"><link rel="prefetch" href="/assets/js/4.862e5a4f.js"><link rel="prefetch" href="/assets/js/5.81a4a7b6.js"><link rel="prefetch" href="/assets/js/7.00cec9d7.js"><link rel="prefetch" href="/assets/js/8.165e4749.js"><link rel="prefetch" href="/assets/js/9.5122111b.js">
    <link rel="stylesheet" href="/assets/css/0.styles.6964efbe.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/logo.png" alt="JavaPool" class="logo"> <span class="site-name can-hide">JavaPool</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <!----></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <!---->  <ul class="sidebar-links"><li><a href="/pages/f0d781/" class="sidebar-link">并发编程三大核心问题</a></li><li><a href="/pages/f94dea/" class="sidebar-link">深入理解线程池</a></li><li><a href="/pages/6c4806/" aria-current="page" class="active sidebar-link">线程池</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/6c4806/#线程池执行流程" class="sidebar-link">线程池执行流程</a></li><li class="sidebar-sub-header level2"><a href="/pages/6c4806/#几种常用的线程池" class="sidebar-link">几种常用的线程池</a></li><li class="sidebar-sub-header level2"><a href="/pages/6c4806/#几种典型的线程池" class="sidebar-link">几种典型的线程池</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/6c4806/#执行流程" class="sidebar-link">执行流程</a></li></ul></li></ul></li><li><a href="/pages/76d299/" class="sidebar-link">并发编程-FutureTask</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><a href="/categories/?category=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="分类" data-v-06225672>并发多线程</a></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="javascript:;" data-v-06225672>未知</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2021-12-27</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">线程池<span class="title-tag">转载</span></h1> <!----> <div class="theme-vdoing-content content__default"><h1 id="java线程池概念"><a href="#java线程池概念" class="header-anchor">#</a> Java线程池概念</h1> <p>顾名思义，管理线程的池子，相比于手工创建、运行线程，使用线程池，有如下优点</p> <p>降低线程创建和销毁线程造成的开销
提高响应速度。任务到达时，相对于手工创建一个线程，直接从线程池中拿线程，速度肯定快很多
提高线程可管理性。线程是稀缺资源，如果无限制地创建，不仅会消耗系统资源，还会降低系统稳定性，使用线程池可以进行统一分配、调优和监控
Java线程池创建
无论是创建何种类型线程池(FixedThreadPool、CachedThreadPool…)，均会调用ThreadPoolExecutor构造函数，下面详细解读各个参数的作用</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">(</span><span class="token keyword">int</span> corePoolSize<span class="token punctuation">,</span>
<span class="token keyword">int</span> maximumPoolSize<span class="token punctuation">,</span>
<span class="token keyword">long</span> keepAliveTime<span class="token punctuation">,</span>
<span class="token class-name">TimeUnit</span> unit<span class="token punctuation">,</span>
<span class="token class-name">BlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span> workQueue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">(</span>corePoolSize<span class="token punctuation">,</span> maximumPoolSize<span class="token punctuation">,</span> keepAliveTime<span class="token punctuation">,</span> unit<span class="token punctuation">,</span> workQueue<span class="token punctuation">,</span>
<span class="token class-name">Executors</span><span class="token punctuation">.</span><span class="token function">defaultThreadFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> defaultHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>corePoolSize:核心线程最大数量，通俗点来讲就是，线程池中常驻线程的最大数量</li> <li>maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)</li> <li>keepAliveTime:线程池中空闲线程（仅适用于非核心线程）所能存活的最长时间</li> <li>unit:存活时间单位，与keepAliveTime搭配使用</li> <li>workQueue：存放任务的阻塞队列</li> <li>handler:线程池饱和策略</li></ul> <h2 id="线程池执行流程"><a href="#线程池执行流程" class="header-anchor">#</a> 线程池执行流程</h2> <p>当提交一个新任务，线程池的处理流程如下：</p> <ul><li><p>判断线程池中核心线程数是否已达阈值corePoolSize,若否，则创建一个新核心线程执行任务</p></li> <li><p>若核心线程数已达阈值corePoolSize,判断阻塞队列workQueue是否已满，若未满，则将新任务添加进阻塞队列</p></li> <li><p>若满，再判断，线程池中线程数是否达到阈值maximumPoolSize,若否，则新建一个非核心线程执行任务。若达到阈值，则执行线程池饱和策略。</p></li></ul> <p>线程池饱和策略分为一下几种：</p> <ul><li>AbortPolicy:直接抛出一个异常，默认策略</li> <li>DiscardPolicy: 直接丢弃任务</li> <li>DiscardOldestPolicy:抛弃下一个将要被执行的任务(最旧任务)</li> <li>CallerRunsPolicy:主线程中执行任务</li></ul> <p>从流程角度，更形象的图：</p> <p><img src="/assets/img/20210707001.30c0e287.png" alt=""></p> <p>从结构角度，更形象的图：</p> <p><img src="/assets/img/20210707002.94b8286a.png" alt=""></p> <h2 id="几种常用的线程池"><a href="#几种常用的线程池" class="header-anchor">#</a> 几种常用的线程池</h2> <ul><li><strong>几种典型的工作队列</strong>
ArrayBlockingQueue:使用数组实现的有界阻塞队列，特性先进先出</li> <li>LinkedBlockingQueue:使用链表实现的阻塞队列，特性先进先出，可以设置其容量，默认为Interger.MAX_VALUE，特性先进先出</li> <li>PriorityBlockingQueue:使用平衡二叉树堆，实现的具有优先级的无界阻塞队列</li> <li>DelayQueue:无界阻塞延迟队列，队列中每个元素均有过期时间，当从队列获取元素时，只有
过期元素才会出队列。队列头元素是最块要过期的元素。</li> <li>SynchronousQueue:一个不存储元素的阻塞队列，每个插入操作，必须等到另一个线程调用移除操作，否则插入操作一直处于阻塞状态</li></ul> <h2 id="几种典型的线程池"><a href="#几种典型的线程池" class="header-anchor">#</a> 几种典型的线程池</h2> <p><strong>SingleThreadExecutor</strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ExecutorService</span> <span class="token function">newSingleThreadExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FinalizableDelegatedExecutorService</span>
<span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token number">0L</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">MILLISECONDS</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">LinkedBlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>创建单个线程。它适用于需要保证顺序地执行各个任务;并且在任意时间点，不会有多个线程是活动的应用场景。</p> <p>SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1，使用无界队列LinkedBlockingQueue作为线程池的工作队列。</p> <p><img src="/assets/img/20210707003.9d3f27fa.png" alt=""></p> <ul><li>当线程池中没有线程时，会创建一个新线程来执行任务。</li> <li>当前线程池中有一个线程后，将新任务加入LinkedBlockingQueue</li> <li>线程执行完第一个任务后，会在一个无限循环中反复从LinkedBlockingQueue 获取任务来执行。</li></ul> <p>**使用场景：**适用于串行执行任务场景</p> <p><strong>FixedThreadPool</strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ExecutorService</span> <span class="token function">newFixedThreadPool</span><span class="token punctuation">(</span><span class="token keyword">int</span> nThreads<span class="token punctuation">,</span> <span class="token class-name">ThreadFactory</span> threadFactory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">(</span>nThreads<span class="token punctuation">,</span> nThreads<span class="token punctuation">,</span>
<span class="token number">0L</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">MILLISECONDS</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">LinkedBlockingQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
threadFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>corePoolSize等于maximumPoolSize,所以线程池中只有核心线程，使用无界阻塞队列LinkedBlockingQueue作为工作队列</p> <p>FixedThreadPool是一种线程数量固定的线程池，当线程处于空闲状态时，他们并不会被回收，除非线程池被关闭。当所有的线程都处于活动状态时，新的任务都会处于等待状态，直到有线程空闲出来。</p> <p><img src="/assets/img/20210707004.dd79c2ad.png" alt=""></p> <ul><li>如果当前运行的线程数少于corePoolSize，则创建新线程来执行任务。</li> <li>在线程数目达到corePoolSize后，将新任务放到LinkedBlockingQueue阻塞队列中。</li> <li>线程执行完(1)中任务后，会在循环中反复从LinkedBlockingQueue获取任务来执行。</li></ul> <p>使用场景：适用于处理CPU密集型的任务，确保CPU在长期被工作线程使用的情况下，尽可能的少的分配线程，即适用执行长期的任务。</p> <p><strong>CachedThreadPool</strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ExecutorService</span> <span class="token function">newCachedThreadPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token constant">MAX_VALUE</span><span class="token punctuation">,</span>
<span class="token number">60L</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span><span class="token constant">SECONDS</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">SynchronousQueue</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Runnable</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>核心线程数为0，总线程数量阈值为Integer.MAX_VALUE,即可以创建无限的非核心线程</p> <h3 id="执行流程"><a href="#执行流程" class="header-anchor">#</a> 执行流程</h3> <ul><li>先执行SynchronousQueue的offer方法提交任务，并查询线程池中是否有空闲线程来执行SynchronousQueue的poll方法来移除任务。如果有，则配对成功，将任务交给这个空闲线程</li> <li>否则，配对失败，创建新的线程去处理任务</li> <li>当线程池中的线程空闲时，会执行SynchronousQueue的poll方法等待执行SynchronousQueue中新提交的任务。若等待超过60s,空闲线程就会终止</li></ul> <p>流程形象图</p> <p><img src="/assets/img/20210707005.869195e5.png" alt="">
结构形象图</p> <p><img src="/assets/img/20210707006.3296ff76.png" alt=""></p> <p>使用场景：执行大量短生命周期任务。因为maximumPoolSize是无界的，所以提交任务的速度 &gt; 线程池中线程处理任务的速度就要不断创建新线程；每次提交任务，都会立即有线程去处理，因此CachedThreadPool适用于处理大量、耗时少的任务。</p> <p><strong>ScheduledThreadPool</strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ScheduledExecutorService</span> <span class="token function">newScheduledThreadPool</span><span class="token punctuation">(</span><span class="token keyword">int</span> corePoolSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ScheduledThreadPoolExecutor</span><span class="token punctuation">(</span>corePoolSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">ScheduledThreadPoolExecutor</span><span class="token punctuation">(</span><span class="token keyword">int</span> corePoolSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>corePoolSize<span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token constant">MAX_VALUE</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token constant">NANOSECONDS</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">DelayedWorkQueue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>线程总数阈值为Integer.MAX_VALUE,工作队列使用DelayedWorkQueue，非核心线程存活时间为0，所以线程池仅仅包含固定数目的核心线程。</p> <p>两种方式提交任务：</p> <ul><li>scheduleAtFixedRate: 按照固定速率周期执行</li> <li>scheduleWithFixedDelay：上个任务延迟固定时间后执行</li></ul> <p><strong>使用场景：周期性执行任务，并且需要限制线程数量的场景</strong></p> <p>面试题：使用无界队列的线程池会导致内存飙升吗？
答案 ：会的，newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue，如果线程获取一个任务后，任务的执行时间比较长，会导致队列的任务越积越多，导致机器内存使用不停飙升， 最终导致OOM。</p> <p>参考博客</p> <ul><li>https://blog.csdn.net/liuchangjie0112/article/details/90698401</li> <li>https://zhuanlan.zhihu.com/p/73990200</li></ul> <div class="custom-block tip"><p class="custom-block-title">来源</p> <p>来源：blog.csdn.net/xuan_lu/article/details/107797505</p></div></div></div> <!----> <div class="page-edit"><!----> <div class="tags"><a href="/tags/?tag=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="标签">#并发多线程</a></div> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/f94dea/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">深入理解线程池</div></a> <a href="/pages/76d299/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">并发编程-FutureTask</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/f94dea/" class="prev">深入理解线程池</a></span> <span class="next"><a href="/pages/76d299/">并发编程-FutureTask</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><div class="icons"><a href="mailto:likanjia@126.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a><a href="https://github.com/" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://music.163.com/#/playlist?id=755597173" title="听音乐" target="_blank" class="iconfont icon-erji"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2019-2023
    <span>likanjie | MIT License</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.c5f14b06.js" defer></script><script src="/assets/js/2.0bb8723e.js" defer></script><script src="/assets/js/6.634b1bae.js" defer></script>
  </body>
</html>
